using QTool.Binary;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Net;
using System.Net.Sockets;
using System.Threading.Tasks;
using UnityEngine;
using QTool.NetFrame.Core;

#if QSteamworks
using Steamworks;
using QSteamworks;
#endif
namespace QTool.NetFrame
{
    public enum ServerMessageType : byte
    {
        GetRoomInfo=10,
        RoomInfo = 110,
        JoinRoom = 13,
        JoinRoomOver = 113,
        MessageList = 67,
        FrameInfo=139,
        InputInfo=39,
        FrameInfoList = 40,
    }
   
    public class ClientInfo : IKey<string>,IKey<QNetConnectId>,IQSerialize
    {
        public string Key { get => id.ToString(); set { } }
        public string deviceId;
        public byte playerId;
        public QNetConnectId id;
        public string playerName="";
        public string playerData = "";
        QNetConnectId IKey<QNetConnectId>.Key { get => id; set => id = value; }



        public QNetFrameRoom roomInfo;
        public ClientInfo(QNetConnectId id)
        {
            this.id = id;
        }
        public override string ToString()
        {
            return "客户端[" + Key + "]";
        }

        public void Write(QBinaryWriter writer)
        {
            writer.Write(playerName);
            writer.Write(playerData);
        }

        public void Read(QBinaryReader reader)
        {
            playerName= reader.ReadString();
            playerData = reader.ReadString();
        }
    }
  
    public class QNetFrameRoom :  IQSerialize
    {
        public string roomName = "测试房间";
        public QControlProtocol network;
        //  public ClientInfo hostInfo;

        List<ClientInfo> clientList = new List<ClientInfo>();
        public List<FrameData> frameList = new List<FrameData>();
        public FrameData curFame=new FrameData();
        public int frameStep;
        public int randomSeed;
        public QNetFrameRoom(int port, int frameStep)
        {
            network = new QControlProtocol(port);
            network.OnMessageReceive += OnReceive;
            network.StartReceive();
            this.frameStep = frameStep;
            StartUpdate();
            randomSeed = new System.Random().Next();
            
        }
        public void Stop()
        {
            network.Close();
        }
        public async void StartUpdate()
        {
            await Task.Delay(2000);
            var startTime = DateTime.Now;
            while (Application.isPlaying)
            {
                CreateFrame();
                var sendDelay = 0;
                lock (frameList)
                {
                   sendDelay = Math.Max(frameStep - (int)((DateTime.Now - startTime).TotalMilliseconds - ((frameList.Count - 1) * (long)frameStep)), 0);
                }
                await Task.Delay(sendDelay);
            }
        }
        private void CreateFrame()
        {
            lock (frameList)
            {
                curFame.id = frameList.Count;
                Send(GetSendBytes(ServerMessageType.FrameInfo, (w) => w.WriteObject(curFame)));
                frameList.Add(curFame);
                curFame = new FrameData();
            }
        }
        public void Add(ClientInfo client)
        {
            clientList.Add(client);
            client.roomInfo = this;
        }
        //public string Key
        //{
        //    get
        //    {
        //        return network.Ip.ToString();
        //    }
        //    set
        //    { }
        //}
        //public async void DelaySend(float time,byte[] bytes, string ip = "", UDPType type = MsgType.重传校验)
        //{
        //    await Tool.DelayGameTime(time, true);
        //    Send(bytes, ip, type);
        //}
        public async void DelaySend(int time, byte[] bytes, string ip = "", MsgType type = MsgType.RSendCheck)
        {
            await Task.Delay(time);
            Send(bytes, ip,type);
        }
        public void Send(byte[] bytes, string ip="", MsgType type = MsgType.RSendCheck)
        {
            if (string.IsNullOrWhiteSpace(ip))
            {
                network.Send(bytes, type, clientList);
            }
            else
            {
                network.Send(bytes, type, clientList.Get(ip).id);

            }
        }
        public static byte[] GetSendBytes(ServerMessageType type, Action<QBinaryWriter> action = null, string fromIp = "")
        {
            using (var writer = new QBinaryWriter())
            {
                writer.Write((byte)type);
                writer.Write(fromIp);
                action?.Invoke(writer);
                var bytes = writer.ToArray();
                return writer.ToArray();
            }
        }
        public void Write(QBinaryWriter write)
        {
            write.Write(roomName);
        }

        public void Read(QBinaryReader read)
        {
            roomName = read.ReadString();
        }


        public override string ToString()
        {
            return "房间[" + roomName + "] 当前玩家数:" + clientList.Count;
        }
        public InputList inputBuffer = new InputList();
        public ClientInfo GetClientByDeviceId(string deviceId,string name)
        {
            foreach (var client in clientList)
            {
                if (client.deviceId == deviceId&&client.playerName==name)
                {
                    return client;
                }
            }
            return null;
        }
        public ClientInfo GetClient(QNetConnectId id,out bool newClient)
        {
            var client = clientList.Get(id.ToString());
            newClient = client == null;
            if (client == null)
            {
                client = new ClientInfo(id);
                client.playerId = (byte)clientList.Count;
            }
            return client;
        }
        public async void OnReceive(byte[] bytes,QNetConnectId id)
        {

            using (var reader = new QBinaryReader(bytes))
            {
                var type = (ServerMessageType)reader.ReadByte();
                var ip = reader.ReadString();
                switch (type)
                {
                    //case ServerMessageType.连接服务器:
                    //    {
                    //        network.Send(GetSendBytes(ServerMessageType.连接服务器成功), MsgType.无校验, RemoteEndPoint);
                    //    }
                    //    break;
                    case ServerMessageType.GetRoomInfo:
                        {
                            network.Send(GetSendBytes(ServerMessageType.RoomInfo, (writer) =>
                            {
                                writer.WriteObject(this);
                            }), MsgType.RSendCheck, id);
                            
                        }
                        break;
                    //case ServerMessageType.创建房间:
                    //    {
                    //        var time = reader.ReadInt32();
                    //        var client = GetClient(RemoteEndPoint);
                    //        var room = new QNetFrameRoom(client, this, time);
                    //        roomList.Add(room);
                    //        QNetDebug.Log("创建房间：" + room);
                    //        room.Send(GetSendBytes(ServerMessageType.创建房间成功, (writer) => {
                    //            writer.WriteObject(roomList);
                    //        }, room.Key), room.Key);
                    //        room.StartUpdate();
                    //    }
                    //    break;
                    case ServerMessageType.JoinRoom:
                        {
                            var deviceId = reader.ReadString();
                            var name = reader.ReadString();
                            var data = reader.ReadString();
                            ClientInfo client = null;
#if QSteamworks
                            if (!QNetManager.Instance.useSteamNet)
#endif
                            {
                                client = GetClientByDeviceId(deviceId,name);
                           
                            }
                            if (client == null) {
                                client=GetClient(id, out var newClient);
                                client.playerName = name;
                                client.deviceId = deviceId;
                                client.playerData = data;
                                if (newClient)
                                {
                                    Add(client);
                                    curFame.AddPlayer(client);
                                }
                            }
                            else
                            {
                                client.id = id;
                            }
                         
                            Send(GetSendBytes(ServerMessageType.JoinRoomOver, (w) => { 
                                w.Write(clientList.IndexOf(client));
                                w.Write(randomSeed); 
                            }, client.Key), client.Key);
                            {
                                var tempList = new List<FrameData>();

                                for (int i = 0; i < frameList.Count; i++)
                                {
                                    lock (frameList)
                                    {
                                        var frame = frameList[i];
                                        tempList.Add(frame);
                                    }
                                    if ((i % 100 == 0 && i != 0) || i == frameList.Count - 1)
                                    {
                                        var sendData = GetSendBytes(ServerMessageType.FrameInfoList, (writer) => writer.WriteObject(tempList));
                                        DelaySend((i / 100 + 1) * 100, sendData, client.Key);
                                        tempList.Clear();
                                    }
                                }
                            }


							Debug.Log(client + "加入 " + this);

                        }
                        break;
                    case ServerMessageType.InputInfo:
                        {
                            inputBuffer.Clear();
                            var client = GetClient(id,out var newClient);
                            inputBuffer = reader.ReadObject(inputBuffer);
                            client.roomInfo?.curFame.SetInputList(client.playerId, inputBuffer);
                            //client.roomInfo?.Send(GetSendBytes(ServerMessageType.帧信息, (writer) => { writer.WriteObject(inputList); }), client.Key);
                        }
                        break;
                    default:
                        break;
                }
            }
        }
    }
    //public class QNetFrameServer1 
    //{
     
    //    List<ClientInfo> clientList = new List<ClientInfo>();
    //    List<QNetFrameRoom> roomList = new List<QNetFrameRoom>();
    //    public UDPNetwork Udp { get; private set; }
    //    public QNetFrameServer(UDPNetwork udp) 
    //    {
    //        this.Udp = udp;
    //        //StartReceive(receiveCount);
    //        QNetDebug.Log("启动中央服务器" + udp.Ip);
    //        udp.OnMessageReceive += OnReceive;
    //    }
     
       
    //}
  
   
}
